package edu.zjucst.spb.service.impl;

import edu.zjucst.spb.domain.entity.flow.FlowUser;
import edu.zjucst.spb.domain.vo.flow.FlowGroupMemberQueryVO;
import edu.zjucst.spb.domain.vo.flow.FlowGroupQueryVO;
import edu.zjucst.spb.enums.FlowBuildExceptionEnum;
import edu.zjucst.spb.exception.BizException;
import edu.zjucst.spb.service.FlowBuildService;
import edu.zjucst.spb.util.converMapper.FlowBuildConvertMapper;
import org.flowable.engine.IdentityService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.repository.Deployment;
import org.flowable.idm.api.Group;
import org.flowable.idm.api.User;
import org.flowable.idm.engine.impl.persistence.entity.GroupEntityImpl;
import org.flowable.idm.engine.impl.persistence.entity.UserEntityImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.UUID;

/**
 * @author ZlunYan
 * @description
 * @create 2023-11-28
 */

@Service
public class FlowBuildServiceImpl implements FlowBuildService {

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private IdentityService identityService;

    @Override
    public Integer addUser(FlowUser flowUser) {
        if (identityService.createGroupQuery().groupName(flowUser.getGroupName()).count() == 0)
            throw new BizException(FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getCode(), FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getDescription());
        if (identityService.createUserQuery().userId(flowUser.getUserId()).count() != 0)
            throw new BizException(FlowBuildExceptionEnum.USER_ID_EXIST.getCode(), FlowBuildExceptionEnum.USER_ID_EXIST.getDescription());

        UserEntityImpl user = new UserEntityImpl();
        user.setId(flowUser.getUserId());
        user.setDisplayName(flowUser.getUsername());
        user.setRevision(0);
        identityService.saveUser(user);
        identityService.createMembership(user.getId(), identityService.createGroupQuery().groupName(flowUser.getGroupName()).singleResult().getId());


        return 1;
    }

    public Integer createUserMemberShip(String userId, String groupName) {
        User user = identityService.createUserQuery().userId(userId).singleResult();
        if (user == null)
            throw new BizException(FlowBuildExceptionEnum.USER_ID_NOT_EXIST.getCode(), FlowBuildExceptionEnum.USER_ID_NOT_EXIST.getDescription());
        Group group = identityService.createGroupQuery().groupName(groupName).singleResult();
        if (group == null)
            throw new BizException(FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getCode(), FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getDescription());
        if (identityService.createUserQuery().memberOfGroup(group.getId()).list().contains(user))
            throw new BizException(FlowBuildExceptionEnum.USER_IN_GROUP.getCode(), FlowBuildExceptionEnum.USER_IN_GROUP.getDescription());

        identityService.createMembership(userId, group.getId());
        return 1;
    }

    public Integer deleteUserMemberShip(String userId, String groupName) {
        User user = identityService.createUserQuery().userId(userId).singleResult();
        if (user == null)
            throw new BizException(FlowBuildExceptionEnum.USER_ID_NOT_EXIST.getCode(), FlowBuildExceptionEnum.USER_ID_NOT_EXIST.getDescription());
        Group group = identityService.createGroupQuery().groupName(groupName).singleResult();
        if (group == null)
            throw new BizException(FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getCode(), FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getDescription());
        if (!identityService.createUserQuery().memberOfGroup(group.getId()).list().contains(user))
            throw new BizException(FlowBuildExceptionEnum.USER_NOT_IN_GROUP.getCode(), FlowBuildExceptionEnum.USER_NOT_IN_GROUP.getDescription());

        identityService.deleteMembership(userId, group.getId());
        return 1;
    }

    public void deleteUserByUserId(String userId) {
        if (identityService.createUserQuery().userId(userId).count() == 0)
            throw new BizException(FlowBuildExceptionEnum.USER_ID_NOT_EXIST.getCode(), FlowBuildExceptionEnum.USER_ID_NOT_EXIST.getDescription());

        identityService.deleteUser(userId);
    }

    public String queryGroupIdByGroupName(String groupName) {
        Group group = identityService.createGroupQuery().groupName(groupName).singleResult();
        if (group != null) return group.getId();
        return null;
    }

    public void deleteGroupByGroupId(String groupId) {
        if (identityService.createGroupQuery().groupId(groupId).count() == 0)
            throw new BizException(FlowBuildExceptionEnum.GROUP_ID_NOT_EXIST.getCode(), FlowBuildExceptionEnum.GROUP_ID_NOT_EXIST.getDescription());
        identityService.deleteGroup(groupId);
    }

    public void deleteGroupByGroupName(String groupName) {
        Group group = identityService.createGroupQuery().groupName(groupName).singleResult();
        if (group == null)
            throw new BizException(FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getCode(), FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getDescription());
        if (identityService.createUserQuery().memberOfGroup(group.getId()).count() != 0)
            throw new BizException(FlowBuildExceptionEnum.GROUP_NOT_EMPTY.getCode(), FlowBuildExceptionEnum.GROUP_NOT_EMPTY.getDescription());


        identityService.deleteGroup(group.getId());
    }

    public void queryGroupCandidateByGroupId(String groupId) {
        List<User> users = identityService.createUserQuery().memberOfGroup(groupId).list();
        for (User user : users) {
            System.out.println("user.getId() = " + user.getId());
            System.out.println("user.getDisplayName() = " + user.getDisplayName());
        }
    }

    public FlowGroupMemberQueryVO queryGroupMemberByGroupName(Integer pageNumber, Integer pageSize, String groupName) {
        Group group = identityService.createGroupQuery().groupName(groupName).singleResult();
        if (group == null)
            throw new BizException(FlowBuildExceptionEnum.GROUP_NAME_NOT_EXIST.getCode(), FlowBuildExceptionEnum.GROUP_NAME_EXIST.getDescription());

        FlowGroupMemberQueryVO vo = new FlowGroupMemberQueryVO();
        List<User> users = identityService.createUserQuery().memberOfGroup(group.getId()).listPage((pageNumber-1) * pageSize, pageSize);

        vo.setFlowUserList(FlowBuildConvertMapper.INSTANCE.userConvertFlowUser(users));

        for (FlowUser user : vo.getFlowUserList()) user.setGroupName(groupName);

        vo.setPages((identityService.createGroupQuery().count() + pageSize - 1)/pageSize);
        vo.setCurrent(pageNumber.longValue());
        vo.setPageSize(pageSize.longValue());
        return vo;
    }

    public FlowGroupQueryVO queryAllGroup(Integer pageNumber, Integer pageSize) {
        FlowGroupQueryVO vo = new FlowGroupQueryVO();
        List<Group> groupList = identityService.createGroupQuery().listPage((pageNumber-1) * pageSize, pageSize);

        vo.setFlowGroupList(FlowBuildConvertMapper.INSTANCE.groupConvertFlowGroup(groupList));
        vo.setPages((identityService.createGroupQuery().count() + pageSize - 1)/pageSize);
        vo.setCurrent(pageNumber.longValue());
        vo.setPageSize(pageSize.longValue());
        return vo;
    }

    public void createMembership(String userId, String groupId) {
        if (identityService.createUserQuery().userId(userId).count() == 0)
            throw new BizException(FlowBuildExceptionEnum.USER_ID_NOT_EXIST.getCode(), FlowBuildExceptionEnum.USER_ID_NOT_EXIST.getDescription());
        if (identityService.createGroupQuery().groupId(groupId).count() == 0)
            throw new BizException(FlowBuildExceptionEnum.GROUP_ID_NOT_EXIST.getCode(), FlowBuildExceptionEnum.GROUP_ID_NOT_EXIST.getDescription());

        identityService.createMembership(userId, groupId);
    }

    @Override
    public Integer createGroup(String groupName) {
        if (identityService.createGroupQuery().groupName(groupName).count() != 0)
            throw new BizException(FlowBuildExceptionEnum.GROUP_NAME_EXIST.getCode(), FlowBuildExceptionEnum.GROUP_NAME_EXIST.getDescription());

        GroupEntityImpl group = new GroupEntityImpl();
        group.setName(groupName);

//        String id = ;
        group.setId(String.valueOf(UUID.nameUUIDFromBytes(groupName.getBytes())));
        group.setRevision(0);
        identityService.saveGroup(group);

        return 1;
    }

    @Override
    public void createDeployment(String filePath, String flowName) {
        Deployment deploy = repositoryService.createDeployment()
            .addClasspathResource(filePath)
            .name(flowName)
            .deploy();
    }
}
